﻿using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Reflection;
using System.Threading;
using System.Security;
using System.Security.Permissions;
using System.Security.Authentication;

namespace WebServer
{
	/// <summary>
	/// Provides a means to store and track connection information for Client connections.
	/// </summary>
	public sealed class Client : IDisposable
	{
		private static int _DefaultRequestLimit = 100;
		/// <summary>
		/// Gets or Sets the default request limit for all clients when they connect.
		/// This value can not be less than 100.
		/// </summary>
		public static int DefaultRequestLimit
		{
			get { return _DefaultRequestLimit; }
			set
			{
				if (value >= 100)
					_DefaultRequestLimit = value;
			}
		}

		private bool _Secured = false;
		/// <summary>
		/// Gets a value indecating that this client is 'Secured'.
		/// </summary>
		public bool Secured { get { return _Secured; } }

		private int _RequestCount = 0;
		/// <summary>
		/// Gets or Sets the current total request buffer for this Client.
		/// </summary>
		public int RequestCount { get { return _RequestCount; } set { _RequestCount = value; } }

		private int _RequestLimit = _DefaultRequestLimit;
		/// <summary>
		/// Gets or Sets the current limit on the total of requests this Client can handle within the Config.ClientFloodThreshold TimeSpan.
		/// </summary>
		public int RequestLimit { get { return _RequestLimit; } set { _RequestLimit = value; } }

		private DateTime _LastActivity = DateTime.Now;
		/// <summary>
		/// The DateTime representation of the last time of activity for this Client
		/// </summary>
		public DateTime LastActivity { get { return _LastActivity; } }

		private bool _AFK = false;
		/// <summary>
		/// Gets a value indecating whether this Client is 'AFK'.
		/// </summary>
		public bool AFK { get { return _AFK; } }

		private bool _Flooding = false;
		/// <summary>
		/// Gets a value indecating whether this Client is 'Flooding'.
		/// </summary>
		public bool Flooding { get { return _Flooding; } }

		private IPEndPoint _IPEndPoint;
		/// <summary>
		/// Gets the IP Address associated with this Client
		/// </summary>
		public IPEndPoint IPEndPoint { get { return _IPEndPoint; } }

		private List<IWebObject> _WebObjects;
		/// <summary>
		/// Gets the web-webObj cache for this Client, storing all WebObjects that have been requested.
		/// </summary>
		public List<IWebObject> WebObjects { get { return _WebObjects; } }

		/// <summary>
		/// Constructs a new instance of Client.
		/// </summary>
		/// <param name="ipep">The IP Address to bind to this Client instance.</param>
		public Client(IPEndPoint ipep)
		{
			_IPEndPoint = ipep;
			_WebObjects = new List<IWebObject>();
		}

		public void Authenticate()
		{

		}

		/// <summary>
		/// Fired when a WebObject is requested.
		/// Refreshes the activity of this Client and computes whether the Client has become 'AFK' or is 'Flooding'
		/// </summary>
		public void OnRequest(HttpListenerContext ctx)
		{
			DateTime now = DateTime.Now;

			_RequestCount++;

			if (_LastActivity.Add(Config.AFKLimit) > now)
				_AFK = false;
			else
				_AFK = true;

			bool isWithinThreshold = (_LastActivity.Add(Config.ClientFloodThreshold) > now);

			if (_RequestCount > _RequestLimit && isWithinThreshold)
			{
				_Flooding = true;
			}
			else
			{
				_Flooding = false;

				if (!isWithinThreshold && _RequestCount > 0)
					_RequestCount = 0;
			}

			_LastActivity = now;
		}

		/// <summary>
		/// Effectively nulliefies all variables, and clears all arrays associated with this Client.
		/// </summary>
		public void Dispose()
		{
			_WebObjects.Clear();
		}

		/// <summary>
		/// Retrieves the string-reprsentation of this instance
		/// </summary>
		/// <returns>'IP Address : Port'</returns>
		public override string ToString()
		{
			return _IPEndPoint.Address.ToString();
		}
	}
}